using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using TelnetExpect;
using System.Diagnostics;

namespace TelnetTests
{
    [TestFixture]
    public class TerminalTelnetHandlerTests : TestsBase
    {
        public TerminalTelnetHandlerTests()
        {
            TestsBase.EnsureConsoleTraceListener();
        }

        protected override TelnetStream Create_Testee(System.IO.Stream conn)
        {
            TelnetStream dut = base.Create_Testee(conn);
            dut.AddOptionHandler(new TerminalTypeHandlerTestee(this));
            return dut;
        }

        int m_width, m_height;

        [Test]
        public void Naws1()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, DO, OptionCode.NegotiateAboutWindowSize,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
                IAC, WILL, OptionCode.NegotiateAboutWindowSize,
                IAC, SB, OptionCode.NegotiateAboutWindowSize,
                    0, 0, // height
                    0, 0, // width
                    IAC, SE, 
            };
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType, TelnetOption.NegotiateAboutWindowSize },
                new TelnetOption[] { });
        }

        [Test]
        public void Naws2()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, DO, OptionCode.NegotiateAboutWindowSize,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
                IAC, WILL, OptionCode.NegotiateAboutWindowSize,
                IAC, SB, OptionCode.NegotiateAboutWindowSize,
                    0, 80, // width
                    0, 24, // height
                    IAC, SE, 
            };
            m_width = 80;
            m_height = 24;
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType, TelnetOption.NegotiateAboutWindowSize },
                new TelnetOption[] { });
        }

        [Test]
        public void Naws3()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, DO, OptionCode.NegotiateAboutWindowSize,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
                IAC, WILL, OptionCode.NegotiateAboutWindowSize,
                IAC, SB, OptionCode.NegotiateAboutWindowSize,
                    255,255, 255,255, // width
                    255,255, 254, // height
                    IAC, SE, 
            };
            m_width = 65535;
            m_height = 65534;
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType, TelnetOption.NegotiateAboutWindowSize },
                new TelnetOption[] { });
        }

        //--------
        const byte TtCommand_Is = 0;
        const byte TtCommand_Send = 1;

        [Test]
        public void Tt_Bad_ShortRequest()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType, IAC, SE,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
            };
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType },
                new TelnetOption[] { });
        }

        [Test]
        public void Tt_Bad_BadCode()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType, 99, IAC, SE,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
            };
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType },
                new TelnetOption[] { });
        }

        //----
        [Test]
        public void Tt()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType, TtCommand_Send, IAC, SE,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType,
                    TtCommand_Is,
                    (byte)'A', (byte)'N', (byte)'S', (byte)'I',
                    IAC, SE, 
            };
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType },
                new TelnetOption[] { });
        }

        [Test]
        public void Tt_twice()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType, TtCommand_Send, IAC, SE,
                IAC, SB, OptionCode.TerminalType, TtCommand_Send, IAC, SE,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType,
                    TtCommand_Is,
                    (byte)'A', (byte)'N', (byte)'S', (byte)'I',
                    IAC, SE, 
                IAC, SB, OptionCode.TerminalType,
                    TtCommand_Is,
                    (byte)'A', (byte)'N', (byte)'S', (byte)'I',
                    IAC, SE, 
            };
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType },
                new TelnetOption[] { });
        }

        [Test]
        public void Tt_thrice()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType, TtCommand_Send, IAC, SE,
                IAC, SB, OptionCode.TerminalType, TtCommand_Send, IAC, SE,
                IAC, SB, OptionCode.TerminalType, TtCommand_Send, IAC, SE,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
                IAC, SB, OptionCode.TerminalType,
                    TtCommand_Is,
                    (byte)'A', (byte)'N', (byte)'S', (byte)'I',
                    IAC, SE, 
                IAC, SB, OptionCode.TerminalType,
                    TtCommand_Is,
                    (byte)'A', (byte)'N', (byte)'S', (byte)'I',
                    IAC, SE, 
                IAC, SB, OptionCode.TerminalType,
                    TtCommand_Is,
                    (byte)'A', (byte)'N', (byte)'S', (byte)'I',
                    IAC, SE, 
            };
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType },
                new TelnetOption[] { });
        }

        [Test]
        public void Tt_wNaws()
        {
            byte[] input = {
                IAC, DO, OptionCode.TerminalType,
                IAC, DO, OptionCode.NegotiateAboutWindowSize,
            };
            byte[] expectedResponses = {
                IAC, WILL, OptionCode.TerminalType,
                IAC, WILL, OptionCode.NegotiateAboutWindowSize,
                IAC, SB, OptionCode.NegotiateAboutWindowSize,
                    0, 80, // width
                    0, 24, // height
                    IAC, SE, 
            };
            m_width = 80;
            m_height = 24;
            DoTest(input, ExpectedInputNone, expectedResponses,
                null,
                new TelnetOption[] { TelnetOption.TerminalType, TelnetOption.NegotiateAboutWindowSize },
                new TelnetOption[] { });
        }

        class TerminalTypeHandlerTestee : TerminalAnsiTelnetHandlerBase
        {
            TerminalTelnetHandlerTests m_parent;

            public TerminalTypeHandlerTestee(TerminalTelnetHandlerTests parent)
            {
                m_parent = parent;
            }

            protected override void GetWindowSize(out int width, out int height)
            {
                width = m_parent.m_width;
                height = m_parent.m_height;
            }

        }

    }
}
